package com.xoms.admin.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.xoms.admin.controller.res.bean.RProStockInBean;
import com.xoms.admin.controller.res.bean.RProStockInInfoBean;
import com.xoms.admin.model.AccountBean;
import com.xoms.admin.model.AuditBean;
import com.xoms.admin.model.ProBreakageBean;
import com.xoms.admin.model.ProStockInBean;
import com.xoms.admin.model.ProStockInDetailBean;
import com.xoms.admin.model.PurchaseBean;
import com.xoms.admin.model.vo.BatchBreakageBean;
import com.xoms.admin.model.vo.BatchStockInBean;
import com.xoms.admin.persist.dao.ProAuditDao;
import com.xoms.admin.persist.dao.ProBreakageDao;
import com.xoms.admin.persist.dao.ProStockInDao;
import com.xoms.admin.persist.dao.PurchaseDao;
import com.xoms.admin.service.ProStockInService;
import com.xoms.admin.service.exception.ServiceException;
import com.xoms.admin.service.res.PageResult;
import com.xoms.util.AppTextUtil;
import com.xoms.util.ArithUtil;
import com.xoms.util.DateTimeUtil;
import com.xoms.util.NumUtil;
import com.xoms.util.StringUtil;

@Service
public class ProStockInServiceImpl implements ProStockInService {

	Logger logger = Logger.getLogger(this.getClass());
	
	@Autowired
	ProStockInDao proStockInImpl;
	
	@Autowired
	ProAuditDao proAuditImpl;
	
	@Autowired
	PurchaseDao purchaseImpl;

	@Autowired
	ProBreakageDao proBreakImpl;


	@Override
	public PageResult<RProStockInBean> getProstockIn(AccountBean account, String key, int page, int pagesize,
			String startTime, String endTime, String storeHouseId) {
		PageResult<RProStockInBean> result = new PageResult<RProStockInBean>();
		List<RProStockInBean> resList = new ArrayList<RProStockInBean>();
		// 查询入库单数量
		int count = proStockInImpl.selectCount(key, storeHouseId, startTime, endTime);
		if (count > 0) {
			// 查询入库单列表
			List<ProStockInBean> lists = proStockInImpl.selectList(key, page, pagesize, storeHouseId, startTime,
					endTime);

			if (lists != null) {
				RProStockInBean rb = null;
				for (ProStockInBean ps : lists) {
					rb = new RProStockInBean();
					rb = parse(ps);
					resList.add(rb);
				}
			}
		}
		result.setData(resList);
		result.setCount(count);
		return result;
	}

	/**
	 * 格式化数据
	 * 
	 * @param stock
	 * @return
	 */
	private RProStockInBean parse(ProStockInBean stock) {
		RProStockInBean res = new RProStockInBean();
		res.setAccount(stock.getAccountId());
		res.setSid(stock.getSid());
		res.setBatch(stock.getBatch());
		res.setType(stock.getType());
		res.setTotalCost(stock.getTotalCost());
		res.setCreateTime(DateTimeUtil.formatTimestamp(stock.getCreateTime()));
		res.setStockInNo(stock.getStockInNo());
		res.setStatus(stock.getStatus());
		res.setTargetId(stock.getTargetId());
		res.setStoreHouse(stock.getStoreHouse());
		res.setStoreHouseId(stock.getStoreHouseId());
		return res;
	}

	@Override
	public PageResult<RProStockInInfoBean> getProstockInDetails(AccountBean account, String key, int page, int pageSize,
			String stockInId, int paging) {
		PageResult<RProStockInInfoBean> result = new PageResult<RProStockInInfoBean>();
		List<RProStockInInfoBean> resList = new ArrayList<RProStockInInfoBean>();
		// 查询入库单数量
		int count = proStockInImpl.selectDetailCount(key, stockInId);
		if(count > 0) {
			//查询入库单列表
			List<ProStockInDetailBean> lists = proStockInImpl.selectDetailList(key, page, pageSize, stockInId, paging);
			if (lists != null) {
				RProStockInInfoBean rb = null;
				for (ProStockInDetailBean stock : lists) {
					rb = new RProStockInInfoBean();
					rb = parseDetail(stock);
					resList.add(rb);
				}
			}
		}
		result.setData(resList);
		result.setCount(count);
		return result;
	}
	
	/**
	 * 格式化数据
	 * @param pur
	 * @return
	 */
	private RProStockInInfoBean parseDetail(ProStockInDetailBean stock) {
		RProStockInInfoBean result = new RProStockInInfoBean();
		result.setUnit(stock.getUnit());
		result.setProduct(stock.getProduct());
		result.setProductId(stock.getProductId());
		result.setCategory(stock.getCategory());
		result.setPrice(stock.getPrice());
		result.setStaleTime(stock.getStaleTime());
		result.setProductBar(stock.getProductBar());
		result.setNumber(stock.getNumber());
		result.setPureNumber(stock.getPureNumber());
		result.setStockInId(stock.getStockInId());
		result.setStockInNo(stock.getStockInNo());
		result.setCreateTime(DateTimeUtil.formatTimestamp(stock.getCreateTime()));
		return result;
	}
	
	/**
	 * 入库：
	 * 	1.从前台获取对应details批量插入
	 *  2.计算数量和实际数量有无变化，将变化的数据提交报损审核
	 *  3.判断数量不能超过关联信息的数量
	 */
	@Transactional(rollbackFor = Exception.class)// 事务
	@Override
	public RProStockInBean insert(AccountBean account, String targetId, String storeId,
			String remark, Double totalCost, String details, int type, int isSubmit) {
		boolean flag = false;
		if(type == 1) { // 入库
			PurchaseBean pur = purchaseImpl.selectOneById(targetId);
			if(pur == null) {
				throw new ServiceException("object_is_not_exist","关联采购单");
			}
			if(pur.getStatus() == 5) {
				throw new ServiceException("purechase_is_stockin");
			}
		} else if(type == 2) { // 冲正入库
			ProStockInBean stock = proStockInImpl.selectOneById(targetId);
			if(stock == null) {
				throw new ServiceException("object_is_not_exist","关联入库单");
			}
			if(stock.getStatus() == 5) {
				throw new ServiceException("stockin_is_reversal");
			}
		}
		String sid = AppTextUtil.getPrimaryKey();// id
		ProStockInBean data = new ProStockInBean();
		data.setSid(sid);
		data.setStoreHouseId(storeId);
		data.setType(type);// 1采购入库2冲正入库3充公入库
		data.setTargetId(targetId);// 关联id
		data.setRemark(remark);
		data.setTotalCost(totalCost);
		// 入库编号：RK +Type + YYYYMMDDHHmm + 0000001;一年百万数据？
		String maxNo = proStockInImpl.selectMaxNoByTypeInYear(type);// 获取当年采购单最大数量
		int num = 0;
		if(!StringUtil.isEmpty(maxNo)) {
			num = NumUtil.toInt(maxNo.substring(maxNo.length() - 7, maxNo.length()), 0);
		}
		String stockInNo = AppTextUtil.getRandomProNo("RK" + type, (num + 1), 7);
		data.setStockInNo(stockInNo);
		data.setAccountId(account.getAccid());
		data.setStatus(isSubmit);// 未提交审核
		
		if(type == 1) { // 入库
			// 将入库商品详情信息批量更新到数据库
			flag = replaceBatchDetailAndBreak(account, data, details);
		} else if(type == 2) {
			// 冲正则直接批量更新数据库
			flag = replaceBatchDetail(account, data, details);
			
		}
		
		if (!flag) {
			throw new ServiceException("database_insert_fail","入库详情订单");
		}
		flag = proStockInImpl.insert(data) > 0;
		if (!flag) {
			throw new ServiceException("database_insert_fail","入库订单");
		}
		// 更新采购单状态
		if(type == 1) { // 入库
			flag = purchaseImpl.updateSubmitStatus(targetId, 5) > 0;
			if (!flag) {
				throw new ServiceException("database_update_fail","采购状态");
			}
		} else if(type == 2) { // 冲正
			flag = proStockInImpl.updateSubmitStatus(targetId, 5) > 0;
			if (!flag) {
				throw new ServiceException("database_update_fail","入库状态");
			}
		}
		
		if(isSubmit == 2) {
			flag = submitAudit(account, data.getSid(), 2);
		}
		
		ProStockInBean res = proStockInImpl.selectOneById(sid);
		return parse(res);
		
	}
	


	@Transactional(rollbackFor = Exception.class)// 事务
	@Override
	public RProStockInBean edit(AccountBean account, String sid, String storeHouseId, Integer type,
			String remark, Double totalCost, String details, int isSubmit) {
		ProStockInBean data = proStockInImpl.selectOneById(sid);
		if(data == null) {
			throw new ServiceException("object_is_not_exist","入库订单");
		}
		if(data.getStatus() != 1 && data.getStatus() != 4) {
			throw new ServiceException("object_is_not_unsubmit", "入库单");
		}
		boolean flag = false;
		data.setSid(sid);
		data.setType(type);
		data.setRemark(remark);
		data.setTotalCost(totalCost);
		data.setStoreHouseId(storeHouseId);
		flag = proStockInImpl.update(data) > 0;
		if (!flag) {
			throw new ServiceException("database_update_fail", "入库");
		}
		// 将入库商品详情信息批量更新到数据库
		int count = proStockInImpl.selectDetailCount(null, sid);
		if(count > 0) {
			flag = proStockInImpl.delDetails(sid) > 0;
			if (!flag) {
				throw new ServiceException("database_delete_fail", "入库单详情");
			}
		}
		flag = replaceBatchDetail(account, data, details);
		return parse(data);
	}
	
	/**
	 * 根据详情更新数据
	 * @param data.
	 * @param details
	 * @return
	 */
	private boolean replaceBatchDetailAndBreak(AccountBean account, ProStockInBean data, String details) {
		boolean flag = false;
		double totalCost = 0;
		// JSON转list，去重
		List<BatchStockInBean> batch = new ArrayList<>(new HashSet<BatchStockInBean>(JSON.parseArray(details, BatchStockInBean.class)));
		if(batch.size() > 0) {
			String sid = data.getSid();
			List<BatchBreakageBean> breaks = new ArrayList<>();
			logger.info("batch:======" + JSON.toJSONString(batch));
			for(BatchStockInBean s : batch) {
				// 判断当前detail中数据是否有变化
				int pureNum = s.getPureNumber();
				if(pureNum > s.getNumber()) {
					BatchBreakageBean b = new BatchBreakageBean();
					b.setProductId(s.getProductId());
					b.setPrice(s.getPrice());
					b.setNumber(s.getNumber());
					breaks.add(b);
				} else if(pureNum < s.getNumber()) {
					throw new ServiceException("object_number_over_error","入库");
				}
				totalCost = ArithUtil.add(totalCost, ArithUtil.mul(s.getNumber(), s.getPrice()));
				s.setStockInId(sid);
			}
			data.setTotalCost(totalCost);
			flag = proStockInImpl.replaceBatchDetail(batch) > 0;
			if (!flag) {
				throw new ServiceException("database_insert_fail","入库订单详情");
			}
			// 判断有无报损，有则需要先删除有无关联的生成报损单
			if(breaks != null && breaks.size() > 0) {
				ProBreakageBean br = proBreakImpl.selectOneByStockId(sid);
				if(br == null) {
					br = new ProBreakageBean();
					br.setStatus(2);
					br.setAccountId(account.getAccid());
					String bid = AppTextUtil.getPrimaryKey();
					br.setBid(bid);
					// 报损编号：BS + YYYYMMDDHHmm + 0000001;一年百万数据？
					String maxNo = proBreakImpl.selectMaxNoInYear();// 获取当年采购报损单最大数量
					int num = 0;
					if(!StringUtil.isEmpty(maxNo)) {
						num = NumUtil.toInt(maxNo.substring(maxNo.length() - 7, maxNo.length()), 0);
					}
					String breakageNo = AppTextUtil.getRandomProNo("BS" , (num + 1), 7);
					br.setBreakageNo(breakageNo);
					br.setRemark("入库时有损耗");
					br.setStockInId(sid);
					br.setStoreHouseId(data.getStoreHouseId());
					flag = createBreakageAndSubmit(br, breaks);

					flag = submitAudit(account, bid, 4);
				} 
				
				
			}
			
		}
		// 
		return flag;
	}
	// 
	private boolean replaceBatchDetail(AccountBean account, ProStockInBean data, String details) {
		boolean flag = false;
		double totalCost = 0;
		// JSON转list，去重
		List<BatchStockInBean> batch = new ArrayList<>(new HashSet<BatchStockInBean>(JSON.parseArray(details, BatchStockInBean.class)));
		if(batch.size() > 0) {
			String sid = data.getSid();
			logger.info("batch:======" + JSON.toJSONString(batch));
			for(BatchStockInBean s : batch) {
				totalCost = ArithUtil.add(totalCost, ArithUtil.mul(s.getNumber(), s.getPrice()));
				s.setStockInId(sid);
			}
			data.setTotalCost(totalCost);
			flag = proStockInImpl.replaceBatchDetail(batch) > 0;
			if (!flag) {
				throw new ServiceException("database_insert_fail","入库订单详情");
			}
		}
		return flag;
	}
	
	// 创建报损订单并提交
	private boolean createBreakageAndSubmit(ProBreakageBean br, List<BatchBreakageBean> breaks) {
		boolean flag = false;
		flag  = proBreakImpl.replace(br) > 0;
		if(!flag) {
			throw new ServiceException("database_update_fail","报损订单");
		}
		for(BatchBreakageBean b : breaks) {
			b.setBreakageId(br.getBid());
		}
		flag = proBreakImpl.replaceBatchDetail(breaks) > 0;
		if(!flag) {
			throw new ServiceException("database_insert_fail","报损订单详情");
		}
		return flag;
	}

	@Transactional(rollbackFor = Exception.class)// 事务
	@Override
	public boolean del(AccountBean account, String sid) {
		boolean flag = false;
		ProStockInBean stockin = proStockInImpl.selectOneById(sid);
		if (stockin == null) { // 入库单不存在
			throw new ServiceException("object_is_not_exist", "入库单");
		}
		if (stockin.getStatus() != 1 ) {// 状态为1才可以删除
			throw new ServiceException("object_is_submit", "入库单");
		}
		flag = proStockInImpl.del(sid) > 0;
		if (!flag) {
			throw new ServiceException("database_delete_fail", "入库单");
		}
		// 删除入库单管理的详情
		int count = proStockInImpl.selectDetailCount(null, sid);
		if(count > 0) {
			flag = proStockInImpl.delDetails(sid) > 0;
			if (!flag) {
				throw new ServiceException("database_delete_fail", "入库单详情");
			}
		}
		
		return flag;
	}

	@Transactional(rollbackFor = Exception.class)// 事务
	@Override
	public boolean submit(AccountBean account, String stockInId) {
		boolean flag = false;
		// 提交入库单前判断是否是待提交状态，提交的采购单不能多次提交
		ProStockInBean stockIn = proStockInImpl.selectOneById(stockInId);
		if(stockIn == null) {// 入库单不存在
			throw new ServiceException("object_is_not_exist","入库单");
		}
		int status = stockIn.getStatus();
		if(status != 1 && status != 4) {
			throw new ServiceException("object_is_not_unsubmit", "入库单");
		}
		flag = proStockInImpl.updateSubmitStatus(stockInId, 2) > 0;// 更新入库状态,1提交待审核
		if (!flag) {// 更新状态失败
			throw new ServiceException("database_update_fail","入库审核状态");
		}
		flag = submitAudit(account, stockInId, 2);
		return flag;
	}

	private boolean submitAudit(AccountBean account, String targetId, int type) {
		boolean flag;
		AuditBean audit = new AuditBean();// 添加到审核表
		audit.setAid(AppTextUtil.getPrimaryKey());
		audit.setSubmitId(account.getAccid());
		audit.setType(type);// 审核类型：1采购2入库3盘库4损耗5充公6冲正7退货到供应商
		audit.setTargetId(targetId);// 关联id
		// 审核编号：SH+ YYYYMMDDHHmm + 0000001;一年百万数据？
		String maxNo = proAuditImpl.selectMaxAuditNoInYear(type);// 获取当年审核单最大数量
		int num = 0;
		if(!StringUtil.isEmpty(maxNo)) {
			num = NumUtil.toInt(maxNo.substring(maxNo.length() - 7, maxNo.length()), 0);
		}
		String auditNo = AppTextUtil.getRandomProNo("SH", (num + 1), 7);
		audit.setAuditNo(auditNo);
		audit.setStatus(0);
				
				
		flag = proAuditImpl.insert(audit) > 0;
		if (!flag) {// 插入状态失败
			throw new ServiceException("database_insert_fail","入库审核提交");
		}
		return flag;
	}
	
}
